package com.hz.foodstalls.security;

import java.util.List;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AccountException;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.util.ByteSource;

import com.hz.foodstalls.model.Admin;
import com.jfinal.ext.kit.Encodes;
import com.jfinal.plugin.ehcache.CacheKit;

/**
 * Created by foodstalls on 2016/2/17.
 */
public class ShiroAuthorizingRealm extends AuthorizingRealm {

    public ShiroAuthorizingRealm() {
        super();
    }

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        if (!SecurityUtils.getSubject().isAuthenticated()) {
            doClearCache(principals);
            SecurityUtils.getSubject().logout();
            return null;
        }
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        // 获取当前登录的用户名
        ShiroPrincipal subject = (ShiroPrincipal) super.getAvailablePrincipal(principals);
        String adminName = subject.getAdminName();
        int adminId = subject.getId();
        try {
            if (!subject.isAuthorized()) {
                // 根据用户名称，获取该用户所有的权限列表
                List<String> authorities = Admin.dao.getAuthoritiesName(adminId);
                List<String> rolelist = Admin.dao.getRolesName(adminId);
                subject.setAuthorities(authorities);
                subject.setRoles(rolelist);
                subject.setAuthorized(true);
            }
        } catch (RuntimeException e) {
            throw new AuthorizationException("用户【" + adminName + "】授权失败");
        }
        // 给当前用户设置权限
        info.addStringPermissions(subject.getAuthorities());
        info.addRoles(subject.getRoles());
        return info;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        UsernamePasswordToken upToken = (UsernamePasswordToken) token;
        String username = upToken.getUsername();

        if (username == null) {
            throw new AccountException("用户名不能为空");
        }

        Admin admin = null;
        try {
            admin = Admin.dao.getAdminByUsername(username);
        } catch (Exception ex) {
        }
        if (admin == null) {
            throw new UnknownAccountException("用户不存在!");
        }
        if (!(admin.getInt("isAccountEnabled") == 1)) {
            throw new UnknownAccountException("用户被禁止使用!");
        }
        if (admin.getInt("isAccountLocked") == 1) {
            throw new LockedAccountException("用户被用户被锁定!");
        }
        byte[] salt = Encodes.decodeHex(admin.getPassword().substring(0, 16));
        ShiroPrincipal subject = new ShiroPrincipal(admin);
        List<String> rolelist = Admin.dao.getRolesName(admin.getId());
        List<String> authorities = Admin.dao.getAuthoritiesName(admin.getId());
        subject.setAuthorities(authorities);
        subject.setRoles(rolelist);
        subject.setAuthorized(true);
        return new SimpleAuthenticationInfo(subject, admin.getPassword().substring(16), ByteSource.Util.bytes(salt),
                getName());
        // return new SimpleAuthenticationInfo(subject,
        // admin.getStr("password"), getName());
    }

    @Override
    protected void doClearCache(PrincipalCollection principals) {
        Object principal = principals.getPrimaryPrincipal();
        CacheKit.getCacheManager().getCache("authenticationCache").remove(principal.toString());
    }

    @Override
    public void setCredentialsMatcher(CredentialsMatcher credentialsMatcher) {
        super.setCredentialsMatcher(initCredentialsMatcher());
    }

    /**
     * 设定密码校验的Hash算法与迭代次数.
     */
    public CredentialsMatcher initCredentialsMatcher() {
        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher("SHA-1");
        matcher.setHashIterations(1024);
        return matcher;
    }

    /**
     * 清空用户关联权限认证,待下次使用时重新加载.在密码修改等情况下，需调用该方法
     */
    public void clearCachedAuthorizationInfo(String principal) {
        SimplePrincipalCollection principals = new SimplePrincipalCollection(principal, getName());
        clearCachedAuthorizationInfo(principals);
    }

    /**
     * 清空所有关联认证.
     */
    public void clearAllCachedAuthorizationInfo() {
        Cache<Object, AuthorizationInfo> cache = getAuthorizationCache();
        if (null != cache) {
            for (Object key : cache.keys()) {
                cache.remove(key);
            }
        }
    }
}
